﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Diagnostics;

namespace HopfieldNetwork
{
    public partial class formMain : Form
    {
        int widthCol;
        int heightRow;

        HopfieldNeuronalNetwork hNet;

        public formMain()
        {
            InitializeComponent();
        }

        private void ClearInput()
        {
            for (int i = 0; i < inputs.Length; i++)
            {
                inputs[i] = -1;
                
            }
            pbImgInput.Refresh();
        }


        private void btCreateWS_Click(object sender, EventArgs e)
        {
            hNet = new HopfieldNeuronalNetwork(NumColumns * NumRows);
            hNet.OnNeuronChangeState += new HopfieldNeuronalNetwork.NeuronChangeState(hNet_OnNeuronChangeState);
            widthCol = pbImage.Width / NumColumns;
            heightRow = pbImage.Height / NumRows;
            tsslbNNeurons.Text += hNet.NumberNeurons;
            ReportEnergy(hNet.Energy);
            Debug.WriteLine(string.Format("Ancho: {0} | Alto: {1} ", widthCol, heightRow));
            nudHeight.Enabled = nudWidth.Enabled = btCreateWS.Enabled = false;

            inputs = new int[hNet.NumberNeurons];
            for (int i = 0; i < inputs.Length; i++)
            {
                inputs[i] = -1;
            }
            pbImgInput.Refresh();
            btAddPattern.Enabled = true;
        }

        void hNet_OnNeuronChangeState(object sender, HopfieldNetwork.Core.NeuronChangeStateEventArgs e)
        {
            ReportEnergy(e.Energy);
            pbImage.Refresh();
        }

        public int NumColumns
        {
            get
            {
                return Convert.ToInt32(nudWidth.Value);
            }
        }

        public int NumRows
        {
            get
            {
                return Convert.ToInt32(nudHeight.Value);
            }
        }

        private void ReportEnergy(double e)
        {
            tsslbEnergy.Text = string.Format("Energia de la Red: {0}", e);
        }

        #region Imagen de Entrada
        int[] inputs;


        private void pbImgInput_MouseClick(object sender, MouseEventArgs e)
        {
            IndexOfClick(e.Location);
        }

        private int IndexOfClick(Point p)
        {
            int idx = -1;
            int xIdx = -1;
            int yIdx = -1;

            xIdx = Convert.ToInt32(p.X / widthCol);
            yIdx = Convert.ToInt32(p.Y / heightRow);
            idx = xIdx + yIdx*NumColumns;

            Debug.WriteLine(string.Format("Click en PB en el x:{0}, y{1}. Neurona:{2}", xIdx, yIdx, idx));

            inputs[idx] *= -1;

            pbImgInput.Refresh();

            
            return idx;
        }

        private void pbImgInput_Paint(object sender, PaintEventArgs e)
        {
            DrawCell(e.Graphics);
            DrawGrid(e.Graphics, pbImgInput.Size.Width, pbImgInput.Size.Height);
        }

        private void DrawCell(Graphics gr)
        {
            if (hNet != null)
            {
                int x = 0;
                int y = 0;
                Brush bAct = null;
                for (int i = 0; i < inputs.Length; i++)
                {

                    bAct = (inputs[i] > 0) ? Brushes.Black : Brushes.White;
                    int rx = x * widthCol;
                    int ry = y * heightRow;
                    gr.FillRectangle(bAct, rx + 1, ry + 1, (rx + widthCol) - 1, (ry + heightRow) - 1);

                    Debug.WriteLine(string.Format("Pintando la celda x:{0},y:{1}", x, y));

                    if (x < (NumColumns - 1))
                    {
                        x++;
                    }
                    else
                    {
                        x = 0;
                        y++;
                    }
                }
            }
        }

        private void DrawGrid(Graphics gr,int maxWidth,int maxHeight)
        {
            if (hNet != null)
            {
                Pen p = new Pen(Brushes.Black);
                for (int i = 1; i < NumColumns; i++)
                {
                    int x = i * widthCol;
                    gr.DrawLine(p, x, 0, x,maxHeight );
                }
                for (int i = 1; i < NumRows; i++)
                {
                    int y = i * heightRow;
                    gr.DrawLine(p, 0, y, maxWidth, y);
                }
            }
        }
        #endregion

        private void btAddPattern_Click(object sender, EventArgs e)
        {
            hNet.AddPattern(inputs);
            ClearInput();
            btAddInput.Enabled = true;
        }

        private void btAddInput_Click(object sender, EventArgs e)
        {
            hNet.Input(inputs);
            btAddPattern.Enabled = false;
            btAddInput.Enabled = false;
            btRun.Enabled = true;
            pbImgInput.Enabled = false;
            pbImage.Refresh();
        }

        private void pbImage_Paint(object sender, PaintEventArgs e)
        {
            DrawNeuronalNetState(e.Graphics);
            DrawGrid(e.Graphics, pbImage.Size.Width, pbImage.Size.Height);
        }

        private void DrawNeuronalNetState(Graphics gr)
        {
            if (hNet!=null && hNet.IsReady)
            {
                Brush bAct = null;
                int x=0;
                int y=0;
                foreach (HopfieldNetwork.Core.Neuron neuron in hNet.Neurons)
                {
                    bAct = (neuron.State > 0) ? Brushes.Black : Brushes.White;
                    int rx = x * widthCol;
                    int ry = y * heightRow;
                    gr.FillRectangle(bAct, rx + 1, ry + 1, (rx + widthCol) - 1, (ry + heightRow) - 1);

                    Debug.WriteLine(string.Format("Pintando la celda x:{0},y:{1}", x, y));

                    if (x < (NumColumns - 1))
                    {
                        x++;
                    }
                    else
                    {
                        x = 0;
                        y++;
                    }
                }    
            }
            
        }

        private void btRun_Click(object sender, EventArgs e)
        {
            btRun.Enabled = false;
            hNet.Run();
            btAddInput.Enabled = true;
            pbImgInput.Enabled = true;
            btRefresh.Enabled = true;
        }

        private void btRefresh_Click(object sender, EventArgs e)
        {
            nudHeight.Enabled = nudWidth.Enabled = btCreateWS.Enabled = true;
            btAddPattern.Enabled = btAddInput.Enabled = btRefresh.Enabled = btRun.Enabled = false;
            ClearInput();
            pbImgInput.Enabled = true;
            btRefresh.Enabled = false;
        }

        private void btAbout_Click(object sender, EventArgs e)
        {
            AboutBox ab = new AboutBox();
            ab.Show();
        }
    }

}
